static
bool hgeCallBackWrap(PyObject * callable,bool defval)
{
	if (!callable) return defval;
	PyObject * ret = PyObject_CallObject(callable,NULL);
	if (!ret)
	{
		PyErr_Print();
		PyErr_Clear();
		return defval;
	}
	int bval = PyObject_IsTrue(ret);
	if (bval == -1)
	{
		PyErr_Print();
		PyErr_Clear();
		return defval;
	}
	bool istrue = bval>0;
	Py_DECREF(ret);
	return istrue;
}
static
bool hgeFrameFuncWrap()
{
	return hgeCallBackWrap(pyFRAMEFUNC,true);//false to continue;
}
static
bool hgeRenderFuncWrap()
{
	return hgeCallBackWrap(pyRENDERFUNC,false);//false is always
}
static
bool hgeGfxRestoreFuncWrap()
{
	return hgeCallBackWrap(pyGFXRESTOREFUNC,false);//true for success,false for fail
}
static
bool hgeFocusLostFuncWrap()
{
	return hgeCallBackWrap(pyFOCUSLOSTFUNC,false);//false is always
}
static
bool hgeFocusGainFuncWrap()
{
	return hgeCallBackWrap(pyFOCUSGAINFUNC,false);//false is always
}
static
bool hgeExitFuncWrap()
{
	return hgeCallBackWrap(pyEXITFUNC,true);//true for exit,false for not exit.
}

static PyObject *
pySystem_Initiate(PyObject *self, PyObject *args)
{
	CHECK_HGE;
	if (!hge->System_Initiate())
	{
		PyErr_SetString(pyHGEError,hge->System_GetErrorMessage());
		return 0;
	}
	Py_RETURN_TRUE;
}

static PyObject *
pySystem_Shutdown(PyObject *self,PyObject *args)
{
	CHECK_HGE;
	hge->System_Shutdown();
	Py_RETURN_NONE;
}

static PyObject *
pySystem_Start(PyObject *self,PyObject *args)
{
	CHECK_HGE;
	if (!hge->System_Start())
	{
		PyErr_SetString(pyHGEError,hge->System_GetErrorMessage());
		return 0;
	}
	Py_RETURN_TRUE;
}
static PyObject *
pySystem_SetState(PyObject *self,PyObject *args)
{
	CHECK_HGE;
	DWORD state;
	PyObject * val;
	PyObject ** ppObj;
	hgeCallback hgecb;
	int bval;
	if (!PyArg_ParseTuple(args,"IO:System_SetState",&state,&val)) return 0;
	switch(state)
	{
	//bool state
	case HGE_WINDOWED:case HGE_ZBUFFER:case HGE_TEXTUREFILTER:case HGE_USESOUND:
	case HGE_DONTSUSPEND:case HGE_HIDEMOUSE:case HGE_SHOWSPLASH:
		bval = PyObject_IsTrue(val);
		if (bval == -1) return 0;
		hge->System_SetState((hgeBoolState)state,(bool)(bval>0));
		break;
	//func state
	case HGE_FRAMEFUNC:
		ppObj = &pyFRAMEFUNC;
		hgecb = hgeFrameFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_RENDERFUNC:
		ppObj = &pyRENDERFUNC;
		hgecb = hgeRenderFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_FOCUSLOSTFUNC:
		ppObj = &pyFOCUSLOSTFUNC;
		hgecb = hgeFocusLostFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_FOCUSGAINFUNC:
		ppObj = &pyFOCUSGAINFUNC;
		hgecb = hgeFocusGainFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_GFXRESTOREFUNC:
		ppObj = &pyGFXRESTOREFUNC;
		hgecb = hgeGfxRestoreFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_EXITFUNC:
		ppObj = &pyEXITFUNC;
		hgecb = hgeExitFuncWrap;
        goto CASE_SET_FUNC;		
	CASE_SET_FUNC:
		if (val == Py_None)
		{
			//clear func
            hge->System_SetState((hgeFuncState)state,NULL);
			Py_XDECREF(*ppObj);
			*ppObj = NULL;
		}
		else if (PyCallable_Check(val) == 1) //callable
		{
			Py_INCREF(val);
			Py_XDECREF(*ppObj);
			*ppObj = val;
			hge->System_SetState((hgeFuncState)state,hgecb);
		}
		else //not callable
		{
			PyErr_SetString(PyExc_TypeError,"Callable object is required.");
			return 0;
		}
		break;
	//hwnd state
	case HGE_HWND:
	case HGE_HWNDPARENT:
		if (PyInt_Check(val) || PyLong_Check(val))
		{
			hge->System_SetState((hgeHwndState)state,(HWND)PyInt_AsUnsignedLongMask(val));
		}
		else
		{
			PyErr_SetString(PyExc_TypeError,"Int object is required.");
			return 0;
		}
		break;
	//int state
	case HGE_SCREENWIDTH:
	case HGE_SCREENHEIGHT:
	case HGE_SCREENBPP:
	case HGE_SAMPLERATE:
	case HGE_FXVOLUME:
	case HGE_MUSVOLUME:
	case HGE_STREAMVOLUME:
	case HGE_FPS:
	case HGE_POWERSTATUS:
		if (PyInt_Check(val) || PyLong_Check(val))
		{
			hge->System_SetState((hgeIntState)state,(int)PyInt_AsLong(val));
		}
		else
		{
			PyErr_SetString(PyExc_TypeError,"Int object is required.");
			return 0;
		}
		break;
	case HGE_ICON:
	case HGE_TITLE:
	case HGE_INIFILE:
	case HGE_LOGFILE:
		if (val == Py_None)
		{
			hge->System_SetState((hgeStringState)state,NULL);
		}
		else if (PyString_Check(val))
		{
			hge->System_SetState((hgeStringState)state,PyString_AS_STRING(val));
		}
		else
		{
			PyErr_SetString(PyExc_TypeError,"String object is required.");
			return 0;
		}
		break;
	default:
		PyErr_SetString(PyExc_ValueError,"Unknown state");
		return 0;
	}
	Py_RETURN_NONE;
}
static PyObject *
pySystem_GetState(PyObject *self,PyObject *args)
{
	CHECK_HGE;
	DWORD state;
	PyObject **ppObj=0;
	hgeCallback hgecb=0;
	if (!PyArg_ParseTuple(args,"I:System_GetState",&state)) return 0;
	switch(state)
	{
	//bool state
	case HGE_WINDOWED:case HGE_ZBUFFER:case HGE_TEXTUREFILTER:case HGE_USESOUND:
	case HGE_DONTSUSPEND:case HGE_HIDEMOUSE:case HGE_SHOWSPLASH:
		if (hge->System_GetState((hgeBoolState)state))
		{
			Py_RETURN_TRUE;
		}
		else
		{
			Py_RETURN_FALSE;
		}
		break;
	//func state
	case HGE_FRAMEFUNC:
		ppObj = &pyFRAMEFUNC;
		hgecb = hgeFrameFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_RENDERFUNC:
		ppObj = &pyRENDERFUNC;
		hgecb = hgeRenderFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_FOCUSLOSTFUNC:
		ppObj = &pyFOCUSLOSTFUNC;
		hgecb = hgeFocusLostFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_FOCUSGAINFUNC:
		ppObj = &pyFOCUSGAINFUNC;
		hgecb = hgeFocusGainFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_GFXRESTOREFUNC:
		ppObj = &pyGFXRESTOREFUNC;
		hgecb = hgeGfxRestoreFuncWrap;
		goto CASE_SET_FUNC;
	case HGE_EXITFUNC:
		ppObj = &pyEXITFUNC;
		hgecb = hgeExitFuncWrap;
		goto CASE_SET_FUNC;		
CASE_SET_FUNC:
		if ( hge->System_GetState((hgeFuncState)state) == NULL )
		{
			Py_RETURN_NONE;
		}
		else
		{
			if (*ppObj == NULL)
			{
				PyErr_SetString(PyExc_SystemError,"Critical error.Maybe a bug.");
				return 0;
			}
			return *ppObj;
		}
		break;
		//hwnd state
	case HGE_HWND:
	case HGE_HWNDPARENT:
		return PyInt_FromSize_t((size_t)hge->System_GetState((hgeHwndState)state));
		break;
	//int state
	case HGE_SCREENWIDTH:
	case HGE_SCREENHEIGHT:
	case HGE_SCREENBPP:
	case HGE_SAMPLERATE:
	case HGE_FXVOLUME:
	case HGE_MUSVOLUME:
	case HGE_STREAMVOLUME:
	case HGE_FPS:
	case HGE_POWERSTATUS:
		return PyInt_FromLong(hge->System_GetState((hgeIntState)state));
		break;
	case HGE_ICON:
	case HGE_TITLE:
	case HGE_INIFILE:
	case HGE_LOGFILE:
		{
			const char * s = hge->System_GetState((hgeStringState)state);
			if (!s)
				return PyString_FromString("");//return None or ""????
			else
				return PyString_FromString(s);
		}
		break;
	default:
		PyErr_SetString(PyExc_ValueError,"Unknown state");
		return 0;
	}
	Py_RETURN_NONE;
}
static PyObject *
pySystem_GetErrorMessage(PyObject *self,PyObject *args)
{
	CHECK_HGE;
	const char * msg = hge->System_GetErrorMessage();
	if (!msg)
	{
		Py_RETURN_NONE;
	}
	return PyString_FromString(msg);
}
static PyObject *
pySystem_Log(PyObject *self,PyObject *args)
{
	CHECK_HGE;
	PyObject * s = NULL;
	PyObject * list = NULL;
	PyObject * s2 = NULL;
	if (!PyTuple_Check(args))
	{
		PyErr_SetString(PyExc_TypeError,"Invalid args.");
		return 0;
	}
	s = PyString_FromString(" ");
	list = PyList_New(0);
	if (!s || !list)
	{
		goto _ERROR;
	}
	for(size_t i=0;i<(size_t)PyTuple_GET_SIZE(args);++i)
	{
		PyObject * item = PyTuple_GetItem(args,i);//borrowed ref
		if (!item)
		{
			goto _ERROR;
		}
		item = PyObject_Str(item);
		if (!item)
		{
			goto _ERROR;
		}
		int ret = PyList_Append(list,item);
		Py_DECREF(item);
		if (ret == -1)
		{
			goto _ERROR;
		}
	}
	s2 = PyObject_CallMethod(s,"join","O",list);
	if (!s2 || !PyString_Check(s2)) goto _ERROR;
	hge->System_Log("%s",PyString_AS_STRING(s2));
	Py_XDECREF(s);
	Py_XDECREF(list);
	Py_XDECREF(s2);
	Py_RETURN_NONE;
_ERROR:
	Py_XDECREF(s);
	Py_XDECREF(list);
	Py_XDECREF(s2);
	return 0;
}
static PyObject *
pySystem_Launch(PyObject *self,PyObject *args)
{
	CHECK_HGE;
	const char * s;
	if (!PyArg_ParseTuple(args,"s:System_Launch",&s))
		return 0;
	hge->System_Launch(s);
	Py_RETURN_NONE;
}
static PyObject *
pySystem_Snapshot(PyObject *self,PyObject *args)
{
	CHECK_HGE;
	const char * s = NULL;
	if (!PyArg_ParseTuple(args,"|s:System_Launch",&s))
		return 0;
	hge->System_Snapshot(s);
	Py_RETURN_NONE;
}